package net.bolue.sysmng.db;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import net.bolue.sysmng.exception.BolueException;
import net.bolue.sysmng.tblbean.DbRes;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class DBPool {

//	private static Logger log = Logger.getLogger(DBPool.class);
	private static DBPool dbPool = new DBPool();
	private static Map<String, ComboPooledDataSource> dataSources = 
			new ConcurrentHashMap<String, ComboPooledDataSource>();
	
	private DBPool() {
		
	}
	
	public final static DBPool getInstance() {
		return dbPool;
	}
	
	public final Connection getConnection(String dbResId) throws BolueException{
		if(dbResId==null||"".equals(dbResId)){
			return null;
		}
		ComboPooledDataSource dataSource = getDataSource(dbResId);
		if(dataSource!=null){
			try {
				Connection conn = dataSource.getConnection();
				return conn;
			} catch (SQLException e) {
				throw new BolueException(9, "不能连接数据库标识："+dbResId, e);
			}
		}else{
			return null;
		}
	}
	
	public final Connection getConnection(DbRes dbRes) throws BolueException{
		if(dbRes==null){
			return null;
		}
		try {
			Connection conn = getDataSource(dbRes).getConnection();
			return conn;
		} catch (SQLException e) {
			throw new BolueException(9, "不能连接数据库标识："+dbRes.getDbResId(), e);
		}
	}
	
	private ComboPooledDataSource getDataSource(String dbResId) {
		ComboPooledDataSource dataSource = dataSources.get(dbResId);
		if (dataSource != null) {
			return dataSource;
		}
		return null;
	}
	
	private ComboPooledDataSource getDataSource(DbRes dbRes) throws BolueException{
		String connName = dbRes.getDbResId();
		ComboPooledDataSource dataSource = dataSources.get(connName);
		if (dataSource != null) {
			return dataSource;
		}
		
		String dbUser = dbRes.getDbUser();
		String dbPwd = dbRes.getPasswd();
		String driver = dbRes.getDbDriver();
		String dbUrl = dbRes.getDbUrl();
		try {
			dataSource = addDataSource(connName,dbUrl,driver,dbUser,dbPwd);
		} catch (PropertyVetoException e) {
//			log.error("生成数据源错误!", e);
			throw new BolueException(9, "生成数据源错误!数据库标识："+connName, e);
		}
		return dataSource;
	}
	
	private ComboPooledDataSource addDataSource(String connName,String dbUrl,
			String driver,String dbUser,String dbPwd) throws PropertyVetoException{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(dbUser);
		dataSource.setPassword(dbPwd);
		dataSource.setJdbcUrl(dbUrl);
		dataSource.setDriverClass(driver);
		/*
		dataSource.setInitialPoolSize(10);
		dataSource.setMinPoolSize(10);
		dataSource.setMaxPoolSize(100);
//		dataSource.setMaxStatements(50);
		dataSource.setMaxIdleTime(20);
		dataSource.setAcquireIncrement(2);
		*/
		/*
		 * 
		dataSource.setInitialPoolSize(1);//初始化时获取三个连接，取值应在minPoolSize与maxPoolSize之间。Default: 3 
		dataSource.setMinPoolSize(1);
		dataSource.setMaxPoolSize(50);
		dataSource.setAcquireIncrement(3);
		dataSource.setMaxIdleTime(300);
		dataSource.setMaxStatements(0);
		dataSource.setIdleConnectionTestPeriod(300);
		*/
		
		dataSource.setBreakAfterAcquireFailure(false);
		//定义在从数据库获取新连接失败后重复尝试的次数。Default: 30
		dataSource.setAcquireRetryAttempts(10);
		//两次连接中间隔时间，单位毫秒。Default: 1000
		dataSource.setAcquireRetryDelay(1000);
		//每60秒检查所有连接池中的空闲连接。Default: 0
		dataSource.setIdleConnectionTestPeriod(30);
		//初始化时获取三个连接，取值应在minPoolSize与maxPoolSize之间。Default: 3 
		dataSource.setInitialPoolSize(1);
		//最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0
		dataSource.setMaxIdleTime(60);
		//连接池中保留的最大连接数。Default: 15
		dataSource.setMaxPoolSize(100);
		dataSource.setMaxStatements(1000);
		//当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3
		dataSource.setAcquireIncrement(3);
		//当连接池用完时客户端调用getConnection()后等待获取新连接的时间，超时后将抛出 
		//SQLException,如设为0则无限期等待。单位毫秒。Default: 0
		dataSource.setCheckoutTimeout(1000);
		dataSource.setUnreturnedConnectionTimeout(20);
//		dataSource.setDebugUnreturnedConnectionStackTraces(true);
		dataSources.put(connName, dataSource);
		return dataSource;
	}
	
	public final void close(Statement pstmt, ResultSet rs, Connection conn) throws BolueException{
		try {
			if (pstmt != null){
				pstmt.close();
			}
			if (rs != null){
				rs.close();
			}
			if (conn != null){
				conn.close();
			}
		} catch (SQLException e) {
			throw new BolueException(9, "关闭连接失败!", e);
//			log.error("关闭连接失败!", e);
		}
	}
}
